/* 
 * 简易搜索引擎, writed by c++
 * author: lurong85
 */

#ifndef _COMMON_ENGINE_H_
#define _COMMON_ENGINE_H_
#include <iostream>
#include <string>
#include <tr1/unordered_set>
#include <tr1/unordered_map>
#include "Segmentor.h"
#include "StringTools.h"

typedef std::tr1::unordered_map<std::string, std::vector<std::string> > IndexMap;
typedef std::tr1::unordered_map<std::string, std::vector<std::string>* > IndexpMap;
typedef std::tr1::unordered_map<std::string, std::string> ForwardMap;

class RankInfo
{
    public:
        RankInfo()
        {
            id = "NULL";
            score = 0.0;
            //shot_num = 0;
            //shotkey_weight_map.clear();
        };
        ~RankInfo(){};
    public:
        std::string id;
        double score;
        //int shot_num;
        //std::tr1::unordered_map<std::string, double> shotkey_weight_map;
};

class Rst{
    public:
        std::string infostr;
    public:
        Rst()
        {
            infostr = "";
        }
        ~Rst(){};
};

class Engine{
    private:
        Engine(){};
        Engine(const Engine& engine){};
        const Engine& operator = (const Engine& engine){};
        ~Engine(){};
        
        static Engine* m_pInstance;

    public:
        static Engine* getInstance()
        {
            if(NULL == m_pInstance)
                m_pInstance = new Engine();
            return m_pInstance;
        }

        static void release()
        {
            if(NULL != m_pInstance)
            {
                delete m_pInstance;
                m_pInstance = NULL;
            }
        }

    private:
        // 正排数据,infostr需要再解析
        ForwardMap _id_infostr_map;
        int loadForwardIndex(const std::string& file_name);

        // 倒排数据,index:idvec一般需要排序
        IndexMap _key_index_map;
        int loadInvertedIndex(const std::string& file_name);

    private:
        // 关键字权重 
        double keywordWeighing(const std::string& key, const double& idf);
        
        // 通过关键字获取倒排索引
        std::vector<std::string>* getIndexpByKey(const std::string& key);
        
        // 获取多个关键字的倒排索引
        int getIndexpMapByKeyVec(std::vector<std::string>& key_vec, IndexpMap& key_indexp_map);
        
        /* 计数求交
         * 这个求交函数，和一般倒排索引的多路求交算法不同
         * 缺点：只适合于数据量不太大的项目（根据经验：数据量不超过500万，平均的倒排索引长度1万左右）
         *       求交速度比多路求交速度慢，但不绝对（适当的控制扫描索引的长度，可以在基本不影响结果的情况下提升效率）
         * 优点：非常简单，易于修改；可以支持一定程度的模糊求交（不严格需要query中的所有词或同义词都出现）
         */
        int countInterset(IndexpMap& key_indexp_map, std::vector<RankInfo>& rankinfo_vec);
        
        // 求交结果的排序
        int rank(std::vector<std::string> key_vec, std::vector<RankInfo>& rankinfo_vec);
        
        // 构造返回结果
        bool formatRst(std::vector<RankInfo>& rankinfo_vec);

    public:
        // 初始化，正排索引和倒排索引
        bool Init(const std::string& fwIndex_file, const std::string& ivIndex_file);

        // 检索函数
        bool Search(std::string& query, std::vector<Rst>& v, const int& ret);

    private:
        // 字符串工具
        StrTools m_st;

        // 分词
        Segmentor m_seg;
};

#endif
